<?php
/**
 * Created by PhpStorm.
 * User: happy
 * Date: 19/4/15
 * Time: 下午10:15
 */
class swoolePlugin extends Plugin{

    private  $server;

    public  $request_callback;
    public  $worker_start_callback;
    public  $receive_callback;
    public  $task_callback;
    public  $worker_finish_callback;
    public  $start_callback;
    public  $master_pid;


    //启动服务程序,有可能一个或者多个
    public function  start_server(){
        $swoole_config=c('swoole');
        //
        if($swoole_config['enable_coroutine']){
            //https://wiki.swoole.com/wiki/page/965.html
            //  Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_FILE);//允许携程
            Swoole\Runtime::enableCoroutine(true);
        }

        $server_type=$swoole_config['server'];
        $swoole_config=$this->handle_swoole_config($swoole_config);
        switch($server_type){
            case 'http'://
                $this->start_http_server($swoole_config);
                break;
            case 'tcp':
               // $server = new tcp_server($config);
                break;
            case 'udp':
               // $server = new udp_server($config);
                break;
            case  'websocket':
               $server = new websocket_server($server_type);
                break;
            default:
                exit('find no recognized server type:'.$server_type);
              //  $server = new tcp_server($config);
                break;
        }
       // $server->start();//启动服务
    }
    //没有端口和ip设置默认的端口和ip,以及worker和task number的数量
     protected  function  handle_swoole_config($config=[]){

         if(!$config['host']){
             echo chr(10).'have no ip config,use 0.0.0.0 instead';
             $config['host']='0.0.0.0';}
         if(!$config['port']){
             $config['port']=8900;
             echo chr(10).'have no server port config,use  8900 instead';
         }

         echo chr(10).'swoole server start on '.$config['port'].':'.$config['host'];


         if(!$config['worker_num']) {
             $config['worker_num']=1;
         }
         if(!$config['task_worker_num']){
             $config['task_worker_num']=1;
         }
         return $config;
     }
    //启动http服务器
    public  function  start_http_server($swoole_config=[]){
          //设置服务器的配置
        $server=$http = new swoole_http_server($swoole_config['host'], $swoole_config['port']);



        $server->set($swoole_config);

        $this->server=$server;

        $this->master_pid= posix_getpid(); // 获取当前进程的 pid

        swoole_set_process_name('swoole_master'); // 修改所在进程的进程名

        $server->on('request', function ($request, $response) {
            //$msg="request Coroutine is ". (Co::getuid() > 0 ? 'enable' : 'disable')."\n";
            //swoole 访问两次的问题
            if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') {
                return $response->end();
            }
            // var_dump($request->get, $request->post);
            //$main='未找到对应的函数!';
            //$_GET=$request->get;
            //$_POST=$request->post;
            $request_callback=$this->request_callback;
            if($request_callback){
                $request_callback($request,$response);
            }
            else{
               $this->default_request_callback($request,$response);
            }
        });

        $server->on('WorkerStart', function($server, $workerId) {
            //$flag=apc_clear_cache();
            opcache_reset();
            echo chr(10).'worker start:'.$workerId.' coroutine_id:'.Co::getuid();
            //此数组中的文件表示进程启动前就加载了，所以无法reload
            global $argv;
            if($workerId >= $server->setting['worker_num']) {
                swoole_set_process_name("php {$argv[0]}: task_worker".$workerId);
            } else {
                swoole_set_process_name("php {$argv[0]}: worker".$workerId);
            }
        });

       // $task_id = $server->task("Async");
        //echo "Dispath AsyncTask: [id=$task_id]\n";
        $server->on('Task', function (swoole_server $server_param, $task_id, $from_id, $data) {
            echo "Tasker进程接收到数据";
            echo "#{$server_param->worker_id}\tonTask: [PID={$server_param->worker_pid}]: task_id=$task_id, data_len=".strlen($data).".".PHP_EOL;
            $server_param->finish($data);
        });

        $server->on('Finish', function (swoole_server $server_param, $task_id, $data) {
            echo "Task#$task_id finished, data_len=".strlen($data).PHP_EOL;
        });

        $start_callback=$this->start_callback;
        if($start_callback){
            $start_callback($server,$this->master_pid);
        }

        $server->start();

    }

    //启动websocket
    public  function  start_socket_server(){

        $server = new swoole_websocket_server("127.0.0.1", 9502);

        $server->on('open', function($server, $req) {
            echo "connection open: {$req->fd}\n";
        });

        $server->on('message', function($server, $frame) {
            echo "received message: {$frame->data}\n";
            $server->push($frame->fd, json_encode(["hello", "world"]));
        });

        $server->on('close', function($server, $fd) {
            echo "connection close: {$fd}\n";
        });

        $server->start();
    }


    //默认回调,解析路由等信息
    protected  function  default_request_callback($request,$response){

        $response->header("Content-Type", "text/html; charset=utf-8");
           $server=$request->server;
            $request_url=trim($server['request_uri'], '/');

            $path_arr=explode('/',$request_url);
            if(count($path_arr)>1){//==1是访问根目录,大于1是访问子目录app
                $app_name=$path_arr[0];
                define('APP_NAME',$app_name);
                $base_path=ROOT_PATH.'/'.$app_name;
                define('BASE_PATH',$base_path);//定义基础目录

                //改变当前目录为app主目录
                if(file_exists($base_path)){
                    chdir($base_path);
                }else{
                    return  $response->end('child dir:'.$app_name.' not exits');
                }
            }
          else{
            return  $response->end('visit root');
          }
          $base_index_path=$base_path.'/index.php';
          if(file_exists($base_index_path)){
            include ($base_index_path);
          }
          //初始化app 内自定义配置
        $GET=$request->get;
        $POST=$request->post;
        $act= $GET['act'] ? strtolower($GET['act']) : ($POST['act'] ? strtolower($POST['act']) : null);
        $op = $GET['op'] ? strtolower($GET['op']) : ($POST['op'] ? strtolower($POST['op']) : null);

        $act = $act ?  $act : 'index';
        $op=$op? $op : 'index';

        $act_file =BASE_PATH.'/control/'.$act.'.php';
        $class_name = $act.'Control';


        if (!class_exists($class_name,false)){
            if(file_exists($act_file)){
                include($act_file);
                if(!class_exists($class_name,false)){
                    $error = "Base Error: class $class_name isn't exists!";
                    return $response->end($error);
                }
            }
            else{
               return $response->end("Base Error: $act_file access file isn't exists!");
            }
        }

        $main = new $class_name($request,$response);
        $function = $op;
        //定义act和op
        if (method_exists($main,$function)){
            $main->$function();
            $main->end();//继承control，无论是否输出都调用一下end结束本次请求
        }else {
            $error = "Base Error: function $function not in $class_name!";
            return $response->end($error);
        }
    }

    public  function  init_server_config($config=[]){
        if($config){
          $this->config=array_merge($this->config,$config);
        }
        else{
            $this->config=array_merge($this->config,c('swoole'));//外部配置输入
        }
    }

    public  function  get_server(){
        return $this->server;
    }

}